Skip to content

feat(agent): maintainer write-actions layer (#778) - #845

Merged
JSONbored merged 1 commit into
mainfrom
feat/agent-write-actions-778
Jun 17, 2026
Merged

feat(agent): maintainer write-actions layer (#778)#845
JSONbored merged 1 commit into
mainfrom
feat/agent-write-actions-778

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Closes #778

What & why

Phase 1 (#769) payoff. gittensory now acts on a PR's statelabelrequest-changesapprovemergeclose — per the repo's autonomy config, ordered least → most irreversible. It never touches source. Everything rides the Phase-0 trust scaffolding and is deny-toward-safety.

Layers

  • src/github/pr-actions.ts — the GitHub write primitives: createPullRequestReview (request-changes/approve), mergePullRequest (with a head-SHA guard so a PR that moved under us fails the merge), closePullRequest, createIssueComment. Thin installation-scoped REST wrappers, mirroring labels.ts.
  • src/settings/agent-actions.tsplanAgentMaintenanceActions: the pure, deterministic verdict→action mapping. Conservative by design:
    • labels by verdict bucket (idempotent — skips if already labeled)
    • requests changes on a blocking verdict / approves a passing one — never both, and never re-posts the same review state
    • merges only a clean, approved, passing PR
    • closes only clear noise (high slop or duplicate) on a non-passing verdict — never both merge and close
  • src/services/agent-action-executor.ts — the gate stack each action passes before any GitHub call:
    pause (#776 kill-switch)approval (auto_with_approval → staged for the #779 queue)write-permission readiness (#775)mode. Only live mutates; dry_run records the intent. Every path writes one agent.action.<class> audit (feat(agent): action audit log + kill-switch + dry-run/shadow mode #776); a failed mutation is recorded as error, never swallowed.
  • processors.ts maybeRunAgentMaintenance — the trigger. After the gate runs on a PR webhook, it recomputes the canonical verdict (confirmed-contributor status + the persisted slop score) and runs the plan through the executor. gittensory never acts on a non-confirmed contributor's PR — the same rule the gate uses to never block one. Best-effort: a failure here never affects the gate or public surface.

Safety

  • Deny-by-default: a repo only acts where it set an acting autonomy level (auto / auto_with_approval); everything else is observe.
  • Dry-run-first: a maintainer flips a repo to agentDryRun to watch the audit feed before going live.
  • Global + per-repo kill-switch honored on every action.
  • auto_with_approval actions are staged, not executed (the approval queue + notifications land in feat(agent): approval-queue UX + notification channel #779).

Scope

Reuses the autonomy / autoMaintain / agentPaused / agentDryRun config from #773/#774/#776no new setting, migration, or config-as-code surface.

Tests

Planner (coherence rules, idempotency, requiresApproval, ordering), executor (live per-class, paused, global kill-switch, approval-staged, permission-denied re-consent, dry-run, error capture, defensive defaults), primitives (each REST shape + sparse-response defaults), and webhook-trigger integration (blocking verdict acts in dry-run; non-acting / non-confirmed / closed-PR / no-stale all no-op). New modules 100% covered (statements + branches); full suite green (2067 passed).

@dosubot dosubot Bot added the size:L label Jun 17, 2026
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jun 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.64%. Comparing base (df4cd7f) to head (cec8ae9).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #845      +/-   ##
==========================================
+ Coverage   96.60%   96.64%   +0.04%     
==========================================
  Files         101      104       +3     
  Lines       14295    14411     +116     
  Branches     5208     5243      +35     
==========================================
+ Hits        13810    13928     +118     
  Misses        105      105              
+ Partials      380      378       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ghost

ghost commented Jun 17, 2026

Copy link
Copy Markdown

gittensory · advisory review

Reviewed 8 changed file(s) — two independent AI reviewers.

Changed files: src/github/pr-actions.ts, src/queue/processors.ts, src/services/agent-action-executor.ts, src/settings/agent-actions.ts, test/unit/agent-action-executor.test.ts, test/unit/agent-actions.test.ts, test/unit/github-pr-actions.test.ts, test/unit/queue.test.ts

Suggested action:Safe to merge — both reviewers found no blocking issues.

Reviewer A · gpt-oss-120b — recommends ✅ merge
The PR introduces a maintainer auto‑maintain layer: planning of GitHub state actions, execution with safety gates, new GitHub primitive wrappers, and extensive unit tests. The implementation is clean, respects the public/private boundary, and integrates safely into the queue processing pipeline.

Suggestions

  • Add a comment in the code clarifying that autoMaintain.requireApprovals defaults to 1 when the policy object is provided without that field, to avoid accidental merge blocks.
  • Consider a unit test for the case where resolveAgentPermissionReadiness receives a null installationPermissions to ensure label actions still succeed and write‑actions are correctly denied.
  • Document the new environment variable AGENT_ACTIONS_PAUSED in the project README where global kill‑switches are described.

Worth double-checking

  • If resolveAgentPermissionReadiness does not handle a null permissions object, non‑label actions could throw; verify its null safety.
  • The default DEFAULT_SLOP_GATE_MIN_SCORE is hard‑coded; future config changes might need to expose it via settings.

Reviewer B · nemotron-3-120b-a12b — recommends ✅ merge
The PR adds a maintainer auto-maintain layer (#778) that plans and executes GitHub state actions (label, review, merge, close) based on gate verdicts and repo autonomy configuration. It includes pure planning logic, a safety-gated executor (pause → approval → write-permission → mode), and low-level GitHub API wrappers. The changes are well-tested with unit tests for all new modules and integration tests in the queue processor. The design respects the public/private boundary by avoiding forbidden terms in templated comments and actions.

No blocking issues spotted.

@ghost

ghost commented Jun 17, 2026

Copy link
Copy Markdown

Note

Gittensory Gate skipped

PR closed before full evaluation. No late first comment was created.

Signal Result Evidence Action
Gate result ⚠️ Skipped #845 is no longer open. No action.

💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.

@ghost ghost added the gittensory:reviewed label Jun 17, 2026
Phase 1 payoff: gittensory acts on a PR's STATE (label / request-changes /
approve / merge / close) per the repo's autonomy config — never on source.
Built on the Phase-0 gates; deny-toward-safety at every step.

Layers:
- src/github/pr-actions.ts — the GitHub write primitives (review / merge with a
  head-sha guard / close / comment). Thin installation-scoped REST wrappers.
- src/settings/agent-actions.ts — planAgentMaintenanceActions: the PURE, conser-
  vative verdict→action mapping. Labels by bucket; requests changes on a blocking
  verdict / approves a passing one (never both, never re-posts the same state);
  merges only a clean, approved, passing PR; closes only clear noise (high slop /
  duplicate) on a non-passing verdict (never both merge and close). Ordered
  least→most irreversible.
- src/services/agent-action-executor.ts — the gate stack each action runs before
  any GitHub call: pause (#776 kill-switch) → approval (auto_with_approval stages
  for the #779 queue) → write-permission readiness (#775) → mode (dry_run records
  the intent, only live mutates). Every path writes one agent.action.<class>
  audit (#776); a failed mutation is recorded as error, never swallowed.
- processors.ts maybeRunAgentMaintenance — the trigger: after the gate runs on a
  PR webhook, recompute the CANONICAL verdict (confirmed-contributor status +
  persisted slop score — gittensory never acts on a non-confirmed contributor's
  PR, same rule the gate uses to never block one), plan, and execute. Best-effort;
  never blocks the gate or public surface.

Reuses the autonomy / autoMaintain / agentPaused / agentDryRun config from
#773/#774/#776 — no new setting, migration, or config-as-code surface. The
auto_with_approval queue UX + notification land in #779.

Tests: planner (coherence rules, idempotency, requiresApproval), executor (live
per-class + paused + global kill-switch + approval-staged + permission-denied +
dry-run + error), primitives (each REST shape), and webhook-trigger integration
(blocking verdict acts in dry-run; non-acting / non-confirmed / closed-PR no-op).
New modules 100% covered; full suite green (2067).
@JSONbored
JSONbored force-pushed the feat/agent-write-actions-778 branch from 5acb4fc to cec8ae9 Compare June 17, 2026 23:18
@JSONbored JSONbored self-assigned this Jun 17, 2026
@JSONbored
JSONbored merged commit 5b53281 into main Jun 17, 2026
20 checks passed
@JSONbored
JSONbored deleted the feat/agent-write-actions-778 branch June 17, 2026 23:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(agent): maintainer write-actions layer (request-changes/approve/merge/close/label)

1 participant